<?php

/**
 * sfValidatorDoctrineUniqueWithConditions  validates that the uniqueness of a column with conditions
 *
 * @package    PSM
 * @subpackage validator
 * @author     Hossam Fares
 * @see feature #5946: Add a new recipient with the same username of deleted recipient is refused while it must add it normally
 * @since 16 Oct 2011
 */
class sfValidatorDoctrineUniqueWithConditions extends sfValidatorDoctrineUnique {

  /**
   * Configures the current validator.
   *
   * Available options:
   *
   *  * model:              The model class (required)
   * 
   *  * column:             The unique column name in Doctrine field name format (required)
   *                        If the uniquess is for several columns, you can pass an array of field names
   * 
   *  * primary_key:        The primary key column name in Doctrine field name format (optional, will be introspected if not provided)
   *                        You can also pass an array if the table has several primary keys
   * 
   *  * connection:         The Doctrine connection to use (null by default)
   * 
   *  * conditions          Condition(s) we want to put in on query used for validation
   * 
   *  * throw_global_error: Whether to throw a global error (false by default) or an error tied to the first field related to the column option array
   *
   * @see sfValidatorBase
   */
    protected function configure($options = array(), $messages = array()) {
        $this->addOption('conditions', null);
        $this->addOption('extraColumn', null);
        parent::configure($options, $messages);
    }

    /**
     * @see sfValidatorBase
     */
    protected function doClean($values) {
        $originalValues = $values;
        $table = Doctrine_Core::getTable($this->getOption('model'));
        if (!is_array($this->getOption('column'))) {
            $this->setOption('column', array($this->getOption('column')));
        }

        //if $values isn't an array, make it one
        if (!is_array($values)) {
            //use first column for key
            $columns = $this->getOption('column');
            $values = array($columns[0] => $values);
        }

        $q = Doctrine_Core::getTable($this->getOption('model'))->createQuery('a');
        foreach ($this->getOption('column') as $column) {
            $colName = $table->getColumnName($column);
            if (!array_key_exists($column, $values)) {
                // one of the column has be removed from the form
                return $originalValues;
            }

            $extraCondition = '';
            if ($this->getOption('extraColumn')){
                foreach ($this->getOption('extraColumn') as $extraColumn) {
                    $extraColName = $table->getColumnName($extraColumn);
                    $extraCondition .= " OR $extraColName = '$values[$column]'";
                }
            }
            $q->addWhere("(a.$colName = '$values[$column]' $extraCondition)");
            
        }
        $conditions = $this->getOption('conditions');
        if (is_array($conditions)) {//If we have conditions in an array loop on it
            foreach ($conditions as $condition) {
                $q->addWhere($condition);//add each contition to the query
            }
        }
        $object = $q->fetchOne();

        // if no object or if we're updating the object, it's ok
        if (!$object || $this->isUpdate($object, $values)) {
            return $originalValues;
        }

        $error = new sfValidatorError($this, 'invalid', array('column' => implode(', ', $this->getOption('column'))));

        if ($this->getOption('throw_global_error')) {
            throw $error;
        }

        $columns = $this->getOption('column');

        throw new sfValidatorErrorSchema($this, array($columns[0] => $error));
    }

}
